using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;

namespace PictureMimic
{
	public class EvolutionHandler
	{
		public bool Running;
		public bool Busy;

		public uint Candidates;
		public uint Generations;

		public Bitmap SourceImage;

		public List<CandidateDNA> MaleCandidates;
		public List<CandidateDNA> FemaleCandidates;

		public CandidateDNA BestCandidate;

		public EvolutionHandler(Bitmap sourceImage)
		{
			Candidates = 0;
			Generations = 0;

			SourceImage = sourceImage;

			MaleCandidates = new List<CandidateDNA>();
			FemaleCandidates = new List<CandidateDNA>();

		}

		public EvolutionHandler(Bitmap sourceImage, List<CandidateDNA> maleAncestors, List<CandidateDNA> femaleAncestors)
		{
			Candidates = 0;
			Generations = 0;

			SourceImage = sourceImage;

			CandidateDNA[] tempMaleArray = maleAncestors.ToArray();
			CandidateDNA[] tempFemaleArray = maleAncestors.ToArray();

			MaleCandidates = new List<CandidateDNA>(tempMaleArray);
			FemaleCandidates = new List<CandidateDNA>(tempFemaleArray);
			
		}

		public void Start()
		{
			Running = true;
			Busy = true;

			if (MaleCandidates.Count < 1)
			{
				CandidateDNA firstMale = new CandidateDNA(Candidates++, Generations);

				firstMale.EvaluateFitness(SourceImage);

				MaleCandidates.Add(firstMale);
			}

			if (FemaleCandidates.Count < 1)
			{
				CandidateDNA firstFemale = new CandidateDNA(Candidates++, Generations);

				firstFemale.EvaluateFitness(SourceImage);

				FemaleCandidates.Add(firstFemale);
			}

			if (MaleCandidates[0].Fitness < FemaleCandidates[0].Fitness)
			{
				BestCandidate = MaleCandidates[0];
			}
			else
			{
				BestCandidate = FemaleCandidates[0];
			}

			Busy = false;

			while (Running)
			{
				// Saftey First!
				if (Generations == uint.MaxValue ||
					Candidates == uint.MaxValue)
				{
					Running = false;
					Busy = false;
					return;
				}

				// OK, Let's Go!

				ushort maleBreederLimit = EvolutionaryConstraints.BreederLimit;
				ushort femaleBreederLimit = EvolutionaryConstraints.BreederLimit;

				if (MaleCandidates.Count < maleBreederLimit)
				{
					maleBreederLimit = (ushort)MaleCandidates.Count;
				}

				if (FemaleCandidates.Count < femaleBreederLimit)
				{
					femaleBreederLimit = (ushort)FemaleCandidates.Count;
				}

				Generations += 1;

				for (int i = 0; i < maleBreederLimit; i++)
				{
					for (int j = 0; j < femaleBreederLimit; j++)
					{
						Candidates += 1;

						CandidateDNA candidate = new CandidateDNA(Candidates++, Generations, MaleCandidates[i], FemaleCandidates[j]);

						candidate.EvaluateFitness(SourceImage);

						if (MaleCandidates.Count < FemaleCandidates.Count)
						{
							MaleCandidates.Add(candidate);
						}
						else
						{
							FemaleCandidates.Add(candidate);
						}
					}

					MaleCandidates.Sort(new CandidateFitnessComparer());
					FemaleCandidates.Sort(new CandidateFitnessComparer());

					if (MaleCandidates.Count > EvolutionaryConstraints.BreederLimit)
					{
						MaleCandidates.RemoveRange(EvolutionaryConstraints.BreederLimit, MaleCandidates.Count - EvolutionaryConstraints.BreederLimit);
					}

					if (FemaleCandidates.Count > EvolutionaryConstraints.BreederLimit)
					{
						FemaleCandidates.RemoveRange(EvolutionaryConstraints.BreederLimit, FemaleCandidates.Count - EvolutionaryConstraints.BreederLimit);
					}

					if (MaleCandidates[0].Fitness < BestCandidate.Fitness)
					{
						Busy = true;
						BestCandidate = MaleCandidates[0];
						Busy = false;
					}

					if (FemaleCandidates[0].Fitness < BestCandidate.Fitness)
					{
						Busy = true;
						BestCandidate = FemaleCandidates[0];
						Busy = false;
					}
				}
			}
		}

		public void Stop()
		{
			Running = false;
		}
	}
}
